/**********************************************************************
	File: noc_testbench.v 
	
	Copyright (C) 2013  Alireza Monemi

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
	
	
	Purpose:

	The NoC testbench file. The NIOS dose not included in testbench.
	the testbench itself control the NI which is connected to NoC routers.
	When compile the code using quartus the NIOS II will be added to code.
	in simulation using modelsim the NIOS processor will be removed and the 
	control pins to NI will be send to simulator. if you just need the 
	simulation define uncomment the " // `define MODEL_TECH " in define.v

	Info: monemi@fkegraduate.utm.my
	
	**********************************************************************/





`timescale 1ns/1ps
`include "define.v"
module noc_testbench();
	`LOG2
	parameter VC_NUM_PER_PORT 			=	4;
	parameter PYLD_WIDTH 				=	32;
	parameter BUFFER_NUM_PER_VC		=	4;
	parameter X_NODE_NUM					=	4;
	parameter Y_NODE_NUM					=	4;
	
	
	parameter NIOS_RAM_WIDTH			=	13;
	parameter S_ADDR_SIZE				=	2;
	parameter PORT_NUM					=	5;
	parameter FLIT_TYPE_WIDTH			=	2;
	
	parameter SDRAM_EN					=	1;//  0 : disabled  1: enabled 
	parameter SDRAM_SW_X_ADDR			=	0;
	parameter SDRAM_SW_Y_ADDR			=	1;
	parameter SDRAM_NIC_CONNECT_PORT	=	0; // if topology is star over mesh and the router is edge router it can be  connected to other port 
	parameter SDRAM_ADDR_WIDTH			=	25;
	parameter CAND_VC_SEL_MODE			=	0;
	
	parameter JTAG_INTERFACE_EN		=	1; // if disabled the jtag can just send packet but can not recieve any packet
	parameter JTAG_SW_X_ADDR			=	0;
	parameter JTAG_SW_Y_ADDR			=	0;
	parameter JTAG_NIC_CONNECT_PORT	=	0;
	parameter PORT_NUM_BCD_WIDTH		=	log2(PORT_NUM);
		
	parameter VC_FULL_WIDTH				=  VC_NUM_PER_PORT*2;
	parameter PORT_SEL_WIDTH			=	PORT_NUM-1;//assum that no port whants to send a packet to itself!
	parameter VC_ID_WIDTH				=	VC_NUM_PER_PORT;
	parameter FLIT_WIDTH					=	PYLD_WIDTH+ FLIT_TYPE_WIDTH+VC_ID_WIDTH;
	parameter FLIT_ARRAY_WIDTH			=	FLIT_WIDTH		*	PORT_NUM;
	parameter CREDIT_ARRAY_WIDTH		=	VC_NUM_PER_PORT	*	PORT_NUM;
	parameter TOTAL_CORES_NUM			=	X_NODE_NUM		* Y_NODE_NUM;
	parameter M_ADDR_SIZE				=	NIOS_RAM_WIDTH+2;
	
	parameter NIC_S_ADDR_ARRAY_WIDTH =	S_ADDR_SIZE*TOTAL_CORES_NUM;
	parameter NIC_S_DATA_ARRAY_WIDTH	=	32 * TOTAL_CORES_NUM;
	parameter RAM_ARRAY_ADDR_WIDTH	=	M_ADDR_SIZE*TOTAL_CORES_NUM;

	localparam X_NODE_NUM_WIDTH		=	log2(X_NODE_NUM);
	localparam Y_NODE_NUM_WIDTH		=	log2(Y_NODE_NUM);
	
	
	localparam SLAVE_RD_PCK_ADDR	=	0;
	localparam SLAVE_WR_PCK_ADDR	=	1;
	localparam SLAVE_STATUS_ADDR	=	2;
	
	parameter CMD_RAM_ADDR_WIDTH	=	5;
	parameter COD_RAM_ADDR_WIDTH	=	8;
	
	localparam	START_CODE			=	(1<< `JTAG_START_LOC);
	localparam	RESET_CODE			=	START_CODE + (1<<`JTAG_NIOS_RST_LOC);
	localparam	BODY_PROG_CODE		=	RESET_CODE + (1<< `JTAG_PROG_START_LOC);
	localparam	FIRST_PROG_CODE	=	BODY_PROG_CODE	 + (1<<`JTAG_FIRST_PART_LOC);
	localparam	TAIL_PROG_CODE		=	BODY_PROG_CODE	+ (1<<`JTAG_LAST_PART_LOC);
	localparam	SDRAM_RW_CODE		=	RESET_CODE + (1<<	`JTAG_RAM_RW_LOC);
	localparam  WRITE_CODE			=	RESET_CODE + (1<<	`JTAG_START_WR_LOC);
	localparam  READ_CODE			=	RESET_CODE + (1<<	`JTAG_START_RD_LOC);
	
	reg													reset;	
	wire 													nios_reset;				
	reg 													clk;
	wire	[TOTAL_CORES_NUM-1			:0]		led;
	
	reg	[TOTAL_CORES_NUM-1			:0]		nic_s_chipselect;
	reg 	[TOTAL_CORES_NUM-1			:0]   	nic_s_write;
	reg	[TOTAL_CORES_NUM-1			:0]   	nic_s_read;
	wire	[TOTAL_CORES_NUM-1			:0]		nic_s_waitrequest;
	reg	[NIC_S_ADDR_ARRAY_WIDTH-1	:0]		nic_s_address_array;  
	reg	[NIC_S_DATA_ARRAY_WIDTH-1	:0]		nic_s_writedata_array;
	wire	[NIC_S_DATA_ARRAY_WIDTH-1	:0] 		nic_s_readdata_array;
	

	reg	[TOTAL_CORES_NUM-1			:0]		ram_we;
	reg	[RAM_ARRAY_ADDR_WIDTH-1		:0]		ram_addr_array;
	reg	[NIC_S_DATA_ARRAY_WIDTH-1	:0]		ram_data_array;
	
	reg   [ 31								:0]		ram_data					[TOTAL_CORES_NUM-1			:0]; 
	reg   [M_ADDR_SIZE-1					:0]		ram_addr					[TOTAL_CORES_NUM-1			:0]; 

	reg 	[S_ADDR_SIZE-1					:0]		nic_s_address			[TOTAL_CORES_NUM-1			:0];   
	reg 	[31								:0]		nic_s_writedata		[TOTAL_CORES_NUM-1			:0];    
	reg	[31								:0] 		nic_s_readdata			[TOTAL_CORES_NUM-1			:0];   

	reg	[31								:0]		cmd_data;
	reg	[CMD_RAM_ADDR_WIDTH-1		:0]		cmd_addr;
	reg													cmd_we;
	wire	[31								:0]		cmd_q_b;
	
	reg	[31								:0]		code_data;
	reg	[COD_RAM_ADDR_WIDTH-1		:0]		code_addr;
	reg													code_we;
	wire													code_q_b;
	
	wire													jtag_led;
	
		wire  [12:0] sdram_addr;        // sdram_.addr
		wire  [1:0]  sdram_ba;          //           .ba
		wire         sdram_cas_n;       //           .cas_n
		wire         sdram_cke;         //           .cke
		wire         sdram_cs_n;        //           .cs_n
		wire   [31:0] sdram_dq;          //           .dq
		wire  [3:0]  sdram_dqm;         //           .dqm
		wire         sdram_ras_n;       //           .ras_n
		wire         sdram_we_n;        //           .we_n
		wire         sdram_clk;          //  sdram_clk.clk

	  
	  
	`include "tasks.v"
	
genvar x,y;
generate 
	for	(x=0;	x<X_NODE_NUM; x=x+1) begin :x_loop1
		for	(y=0;	y<Y_NODE_NUM;	y=y+1) begin: y_loop1
			always @(*) begin
				ram_data_array	[(`CORE_NUM(x,y)+1)*32-1						: `CORE_NUM(x,y)*32				] = ram_data			[`CORE_NUM(x,y)];
				ram_addr_array [(`CORE_NUM(x,y)+1)*M_ADDR_SIZE-1			: `CORE_NUM(x,y)*M_ADDR_SIZE	] = ram_addr			[`CORE_NUM(x,y)];
				nic_s_address_array 	[(`CORE_NUM(x,y)+1)*S_ADDR_SIZE-1	: `CORE_NUM(x,y)*S_ADDR_SIZE	] = nic_s_address 	[`CORE_NUM(x,y)];
				nic_s_writedata_array[(`CORE_NUM(x,y)+1)*32-1				: `CORE_NUM(x,y)*32				] = nic_s_writedata	[`CORE_NUM(x,y)];
				nic_s_readdata	[`CORE_NUM(x,y)] = nic_s_readdata_array	[(`CORE_NUM(x,y)+1)*32-1	: `CORE_NUM(x,y)*32] ;
			end
		end
	end
endgenerate
	
	
	mpsoc #(

		.VC_NUM_PER_PORT 			(VC_NUM_PER_PORT),
		.PYLD_WIDTH 				(PYLD_WIDTH),
		.BUFFER_NUM_PER_VC		(BUFFER_NUM_PER_VC),
		.FLIT_TYPE_WIDTH			(FLIT_TYPE_WIDTH),
		.PORT_NUM					(PORT_NUM),
		.X_NODE_NUM					(X_NODE_NUM),
		.Y_NODE_NUM					(Y_NODE_NUM),
		.S_ADDR_SIZE				(S_ADDR_SIZE),
		.NIOS_RAM_WIDTH			(NIOS_RAM_WIDTH),
		
		.SDRAM_EN					(SDRAM_EN),//  0 : disabled  1: enabled 
		.SDRAM_SW_X_ADDR			(SDRAM_SW_X_ADDR),
		.SDRAM_SW_Y_ADDR			(SDRAM_SW_Y_ADDR),
		.SDRAM_NIC_CONNECT_PORT	(SDRAM_NIC_CONNECT_PORT	), // if topology is star over mesh and the router is edge router it can be  connected to other port 
		.SDRAM_ADDR_WIDTH			(SDRAM_ADDR_WIDTH),
		.CAND_VC_SEL_MODE			(CAND_VC_SEL_MODE),
		
		.JTAG_INTERFACE_EN		(JTAG_INTERFACE_EN), // if disabled the jtag can just send packet but can not recieve any packet
		.JTAG_SW_X_ADDR			(JTAG_SW_X_ADDR),
		.JTAG_SW_Y_ADDR			(JTAG_SW_Y_ADDR),
		.JTAG_NIC_CONNECT_PORT	(JTAG_NIC_CONNECT_PORT)
	
	)
	the_mpsoc
	(
		.reset						(reset),	
		.nios_reset					(nios_reset),				
		.clk							(clk),
		.led							(led),
		.jtag_led					(jtag_led),
		
		.nic_s_chipselect			(nic_s_chipselect),
		.nic_s_write				(nic_s_write),
		.nic_s_read					(nic_s_read),
		.nic_s_waitrequest		(nic_s_waitrequest),
		.nic_s_address_array		(nic_s_address_array),  
		.nic_s_writedata_array	(nic_s_writedata_array),
		.nic_s_readdata_array 	(nic_s_readdata_array),
		
		.cmd_data					(cmd_data),
		.cmd_addr					(cmd_addr),
		.cmd_we						(cmd_we),
		.cmd_q_b						(cmd_q_b),
		
		.code_data					(code_data),
		.code_addr					(code_addr),
		.code_we						(code_we),
		.code_q_b					(code_q_b),
		
		.ram_we						(ram_we),
		.ram_addr_array			(ram_addr_array),
		.ram_data_array			(ram_data_array),
		
		.sdram_addr					(sdram_addr) ,	
		.sdram_ba					(sdram_ba) ,	
		.sdram_cas_n				(sdram_cas_n) ,	
		.sdram_cke					(sdram_cke) ,	
		.sdram_cs_n					(sdram_cs_n) ,	
		.sdram_dq					(sdram_dq) ,	
		.sdram_dqm					(sdram_dqm) ,	
		.sdram_ras_n				(sdram_ras_n) ,	
		.sdram_we_n					(sdram_we_n) ,	
		.sdram_clk					(sdram_clk) 	
		
		
		
		
	);
	
	generate 
	if (SDRAM_EN) begin 
	
		sdram_sdram_controller_test_component sdram_test_component(
			 // inputs:
			.clk			(clk),
			.zs_addr		(sdram_addr),
			.zs_ba		(sdram_ba),
			.zs_cas_n	(sdram_cas_n),
			.zs_cke		(sdram_cke),
			.zs_cs_n		(sdram_cs_n),
			.zs_dqm		(sdram_dqm),
			.zs_ras_n	(sdram_ras_n),
			.zs_we_n		(sdram_we_n),
			// outputs:
			.zs_dq		(sdram_dq)
		);
	end
	endgenerate
	
	
	
	initial begin
			cmd_data					= 0;
			cmd_addr					= 0;
			cmd_we					= 0;
	
			code_data				= 0;
			code_addr				= 0;
			code_we					= 0;
	end
	
	genvar i;
	generate 
	for(i=0; i< TOTAL_CORES_NUM; i=i+1) begin : ll
		initial begin
			ram_data[i]				= 0;
			ram_addr[i]				= 0;
			ram_we[i] 				= 1'b0;
			nic_s_address	[i]	= 0	; 
			nic_s_chipselect[i]	=	1'b0;
			nic_s_write	[i]		=	1'b0;	
			nic_s_read [i]			=	1'b0;
			nic_s_writedata [i]	= 0;
		end
	end
	endgenerate
	
	
	initial begin
		clk=0;
		forever clk=#10 ~clk;
	end

	initial begin
		reset=1;
		#50
		reset=0;
	end


	//test programmer 
	integer k,j;
initial begin
	 
	
/*	
	
//repeat(2) begin	
  	# 200
	//update_cmd_mem (des_x_addr,des_y_addr,jtag_mem_start_addr, pckt_size,sdram_start_addr)
	update_cmd_mem ( 0,2,0,(2**COD_RAM_ADDR_WIDTH),5000);
	
	

	# 1000
	
	send_cmd( FIRST_PROG_CODE	);
		
	$display($time,"first  part has been  sent");
	
	repeat(2) begin 
		# 200
		send_cmd(  BODY_PROG_CODE);
	end
	
	# 200
	send_cmd( TAIL_PROG_CODE);			
		
	$display($time,"prog is finished");
	*/
	
	//test sdram wrire
	//update_cmd_mem (des_x_addr,des_y_addr,jtag_mem_start_addr, pckt_size,sdram_start_addr)
	//update_cmd_mem ( SDRAM_SW_X_ADDR,SDRAM_SW_Y_ADDR,0,(2**COD_RAM_ADDR_WIDTH),5000);
	//#100
	//send_cmd( SDRAM_RW_CODE);
	//$display($time,"sdram write command has been sent");
	//#100
	//update_cmd_mem ( SDRAM_SW_X_ADDR,SDRAM_SW_Y_ADDR,0,(2**COD_RAM_ADDR_WIDTH),50000);
	//#100
	//send_cmd( SDRAM_RW_CODE);
	//$display($time,"sdram write command has been sent");
	//#100
	
	/*
	repeat(50)begin
	update_cmd_mem ( SDRAM_SW_X_ADDR,SDRAM_SW_Y_ADDR,0,50,5000);
	#100
	send_cmd( SDRAM_RW_CODE);
	$display($time,"sdram write command has been sent");
	
	//test sdram read
	
	//write_read_req ( jtag_mem_start_addr, pckt_size, sdram_start_addr);
	write_read_req ( 0, 50,5000);
	send_cmd(WRITE_CODE);
	
	while (cmd_q_b[`JTAG_HAS_DATA_LOC]== 1'b0) begin 
		#100
		send_cmd(START_CODE);
		wait (cmd_q_b[`JTAG_HAS_DATA_LOC] ) ;	
	end
	update_cmd_mem ( SDRAM_SW_X_ADDR,SDRAM_SW_Y_ADDR,0,100,5000);
	send_cmd(READ_CODE);
end

*/











end
	


	
	integer	counter1;
	initial begin
		
	# 200
	
	for(counter1 = 0; counter1 <100; counter1 =counter1 +1'b1) begin
	  #20
	send_pck( 0,2,3,2,20,counter1* 21*4);	

	
	
	end
	
	end
	
	
	integer	counter3;
	initial begin
		
	# 200
	
	for(counter3 = 0; counter3 <100; counter3 =counter3 +1'b1) begin
	  #20
	send_pck( 1,2,3,2,20,counter3* 21*4);	

	
	
	end
	
	end
	
	integer	counter4;
	initial begin
		
	# 200
	
	for(counter4 = 0; counter4 <100; counter4 =counter4 +1'b1) begin
	  #20
	send_pck( 1,3,3,2,20,counter4* 21*4);	

	
	
	end
	
	end
	
	
	integer	counter5;
	initial begin
		
	# 200
	
	for(counter5 = 0; counter5 <100; counter5 =counter5 +1'b1) begin
	  #20
	send_pck( 2,2,3,2,20,counter5* 21*4);	

	
	
	end
	
	end
	

	
	integer	counter2;
	initial begin
		# 300
		for(counter2 = 0; counter2 <400; counter2 =counter2 +1'b1) begin
			
			recive_pck(3,2,200,counter2 *21*4);
			
			$display("total of %d pcks has been recieved",counter2+1);
			
		end
	end
	



endmodule


